package com.dkts.oil.exception;

import com.dkts.oil.constant.ExceptionEnum;
import com.dkts.oil.web.vo.response.Result;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.util.List;
import java.util.Objects;

@ControllerAdvice
@Slf4j
public class SpringExceptionHandler {

    private final String notNull = "NotNull";
    private final String notEmpty = "NotEmpty";
    private final String notBlank = "NotBlank";

    @ExceptionHandler({
            MissingServletRequestParameterException.class,
            MethodArgumentTypeMismatchException.class,
            MethodArgumentNotValidException.class,
            HttpRequestMethodNotSupportedException.class,
            HttpMediaTypeNotSupportedException.class,
            HttpMessageNotReadableException.class,
            OilException.class,
            BindException.class,
            RuntimeException.class
    })
    public @ResponseBody Result handleSpecificExceptions(Exception e, HttpServletRequest request) {
        log.error("ExceptionHandler, Http Request URI: {}", request.getRequestURI(), e);

        if (e instanceof MissingServletRequestParameterException) {
            return Result.createError(ExceptionEnum.PARAM_ERROR.getCode(), ((MissingServletRequestParameterException) e).getParameterName());
        } else if (e instanceof MethodArgumentTypeMismatchException) {
            String msg = String.format("参数类型不正确，接口:%s, 期望参数类型：%s, 参数：%s",
                    Objects.requireNonNull(((MethodArgumentTypeMismatchException) e).getParameter().getMethod()).getName(),
                    ((MethodArgumentTypeMismatchException) e).getParameter().getParameterType(),
                    ((MethodArgumentTypeMismatchException) e).getName());
            return Result.createError(ExceptionEnum.PARAM_ERROR.getCode(), msg);
        } else if (e instanceof HttpRequestMethodNotSupportedException) {
            String msg = "请求方式应为:" + ((HttpRequestMethodNotSupportedException) e).getSupportedHttpMethods()
                    + "，错误信息:" + ((HttpRequestMethodNotSupportedException) e).getMessage();
            return Result.createError(ExceptionEnum.NOT_SUPPORTED_ERROR_CODE.getCode(), msg);
        } else if (e instanceof HttpMediaTypeNotSupportedException) {
            String msg = "不支持的媒体类型:" + ((HttpMediaTypeNotSupportedException) e).getSupportedMediaTypes()
                    + "，错误信息:" + ((HttpMediaTypeNotSupportedException) e).getMessage();
            return Result.createError(ExceptionEnum.NOT_SUPPORTED_ERROR_CODE.getCode(), msg);
        } else if (e instanceof HttpMessageNotReadableException) {
            return Result.createError(ExceptionEnum.NOT_SUPPORTED_ERROR_CODE.getCode(), "请求参数值不正确");
        } else if (e instanceof OilException) {
            return ((OilException) e).getResult();
        } else if (e instanceof BindException || e instanceof MethodArgumentNotValidException) {
            List<FieldError> fieldErrors = ((BindingResult) e).getFieldErrors();
            if (!fieldErrors.isEmpty()) {
                FieldError error = fieldErrors.get(0);
                int codeIndex = notNull.equals(error.getCode()) || notEmpty.equals(error.getCode()) || notBlank.equals(error.getCode())
                        ? ExceptionEnum.PARAM_IS_NULL.getCode() : ExceptionEnum.PARAM_ERROR.getCode();
                return Result.createError(codeIndex, error.getField()+":"+error.getDefaultMessage());
            }
        }else if (e instanceof IllegalArgumentException) {
            return Result.createError(ExceptionEnum.PARAM_ERROR.getCode(), e.getMessage());
        }else if (e instanceof RuntimeException) {
            return Result.createError(ExceptionEnum.PARAM_ERROR.getCode(), "服务端运行错误，请联系管理员");
        }

        return Result.createError(ExceptionEnum.UNKNOWN_ERROR, e.getMessage());
    }
    @ExceptionHandler(IllegalArgumentException.class)
    public @ResponseBody Result illegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
        return Result.createError(ExceptionEnum.PARAM_ERROR.getCode(), e.getMessage());
    }
    @ExceptionHandler(Exception.class)
    public @ResponseBody Result handleGeneralException(Exception e, HttpServletRequest request) {
        log.error("ExceptionHandler, Http Request URI: {}", request.getRequestURI(), e);
//        return Result.createError(ExceptionEnum.UNKNOWN_ERROR);
        return handleSpecificExceptions(e, request);
    }
}
